package com.duubee.btframe.service.impl;

import com.baomidou.mybatisplus.annotation.TableName;
import com.duubee.btframe.utils.BtFieldUtil;
import com.duubee.btframe.vo.BtCondition;
import com.duubee.btframe.vo.lambda.BtConditionLambda;
import com.duubee.btframe.utils.BtFrameUtil;
import com.duubee.btframe.service.BtCommonService;
import com.duubee.btframe.service.BtService;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.util.Annotations;

import javax.annotation.Resource;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@SuppressWarnings("unused")
public class BtServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements BtService<T> {

    @Resource
    private BtCommonService btCommonService;

    @Override
    public IPage<T> queryByPaging(Page btPage, BtCondition btCondition) {
        return btCommonService.queryByPaging(getEntityClass(), btPage, btCondition);
    }

    @Override
    public T querySingleById(Serializable id) {
        return btCommonService.querySingleById(getEntityClass(), id);
    }

    @Override
    public T querySingle(BtCondition btCondition) {
        return btCommonService.querySingle(getEntityClass(), btCondition);
    }

    @Override
    public T querySingleLimit(BtCondition btCondition) {
        return btCommonService.querySingleLimit(getEntityClass(), btCondition);
    }

    @Override
    public List<T> queryList() {
        return btCommonService.queryList(getEntityClass(), null);
    }

    @Override
    public List<T> queryList(BtCondition btCondition) {
        return btCommonService.queryList(getEntityClass(), btCondition);
    }

//    @Override
//    public boolean save(T entity) {
//        return btCommonService.save(entity);
//    }

//    @Override
//    public <T> boolean insert(T entity) {
//        return btCommonService.insert(entity);
//    }

    @Override
    public boolean updateByIdBt(T entity) {
        return btCommonService.updateById(entity);
    }

    @Override
    public boolean updateByCondition(T entity, BtCondition btCondition) {
        return btCommonService.updateByCondition(entity, btCondition);
    }

    @Override
    public boolean removeByIdBt(Serializable id) {
        return btCommonService.removeById(this.getEntityClass(), id);
    }

    @Override
    public boolean removeByCondition(BtCondition btCondition) {
        return btCommonService.removeByCondition(this.getEntityClass(), btCondition);
    }

    @Override
    public long count(BtCondition btCondition) {
        return btCommonService.count(this.getEntityClass(), btCondition);
    }


    @Override
    public boolean saveOrUpdateByUNIQUE(T entity, BtCondition btCondition) {
        return btCommonService.saveOrUpdateByUNIQUE(entity, btCondition);
    }

    @Override
    public boolean logicRemoveById(Serializable id) {

        try {
            Class<T> t = this.getEntityClass();
            T tObject = t.newInstance();

            Field[] fields = BtFieldUtil.getAllFieldsByClass(t);

            Field deletedField = BtFrameUtil.getLogicDeletedField(fields);

            if (deletedField == null) {
                throw new RuntimeException("logicRemoveById not found BtLogicDeleted Field");
            }

            deletedField.setAccessible(true);
            deletedField.set(tObject, true);

            Field tableId = BtFrameUtil.getTableId(fields);
            tableId.setAccessible(true);

            if (tableId.getType() == Integer.class) {
                tableId.set(tObject, Integer.valueOf(id.toString()));
            } else {
                tableId.set(tObject, id);
            }

            return this.updateById(tObject);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;

    }

    @Override
    public boolean logicRemoveByIds(Collection<? extends Serializable> idList) {
        try {
            Class<T> t = this.getEntityClass();
            Field[] fields = t.getDeclaredFields();

            Field deletedField = BtFrameUtil.getLogicDeletedField(fields);

            if (deletedField == null) {
                throw new RuntimeException("logicRemoveByIds not found BtLogicDeleted Field");
            }

            deletedField.setAccessible(true);
            Field tableId = BtFrameUtil.getTableId(fields);
            tableId.setAccessible(true);

            List<T> updateObjectList = new ArrayList<>();
            Object[] idArray = idList.toArray();
            for (int i = 0; i < idList.size(); i++) {
                T tObject = t.newInstance();
                if (tableId.getType() == Integer.class) {
                    tableId.set(tObject, Integer.valueOf(idArray[i].toString()));
                } else {
                    tableId.set(tObject, idArray[i]);
                }
                deletedField.set(tObject, true);
                updateObjectList.add(tObject);
            }

            return this.updateBatchById(updateObjectList);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 获取实体类Class
     *
     * @return 实体类型
     */
    @SuppressWarnings("ALL")
    private Class<T> getEntityClass() {
        Type[] tType = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();

        List<Type> type = Arrays.stream(tType).filter(item -> ((Class<?>) item).isAnnotationPresent(TableName.class)).collect(Collectors.toList());
        if (type.size() > 0) {
            return (Class<T>) type.get(0);
        }
        return (Class<T>) tType[tType.length - 1];
    }

    @Override
    public IPage<T> queryByPaging(Page btPage, BtConditionLambda<T> btConditionLambda) {
        return this.queryByPaging(btPage, btConditionLambda.getBtCondition());
    }

    @Override
    public T querySingle(BtConditionLambda<T> btConditionLambda) {
        return this.querySingle(btConditionLambda.getBtCondition());
    }

    @Override
    public T querySingleLimit(BtConditionLambda<T> btConditionLambda) {
        return this.querySingleLimit(btConditionLambda.getBtCondition());
    }

    @Override
    public List<T> queryList(BtConditionLambda<T> btConditionLambda) {
        return this.queryList(btConditionLambda.getBtCondition());
    }

    @Override
    public boolean updateByCondition(T entity, BtConditionLambda<T> btConditionLambda) {
        return this.updateByCondition(entity, btConditionLambda.getBtCondition());
    }

    @Override
    public boolean removeByCondition(BtConditionLambda<T> btConditionLambda) {
        return this.removeByCondition(btConditionLambda.getBtCondition());
    }

    @Override
    public long count(BtConditionLambda<T> btConditionLambda) {
        return this.count(btConditionLambda.getBtCondition());
    }

    @Override
    public boolean saveOrUpdateByUNIQUE(T entity, BtConditionLambda<T> btConditionLambda) {
        return this.saveOrUpdateByUNIQUE(entity, btConditionLambda.getBtCondition());
    }
}
